// add
function addEventListener(type, listener, listeners) {
    if (typeof type === "string" && typeof listener === "function") {
        if (listeners[type]) {
            if (listeners[type].indexOf(listener) < 0) {
                listeners[type].push(listener);
            }
        } else {
            listeners[type] = [listener];
        }
    }
}

// remove
function removeEventListener(type, listener, listeners) {
    if (listeners[type]) {
        let index = getEventsIndex(listener, listeners[type]);
        if (index > -1) {
            listeners[type].splice(index, 1);
        }
    }
}

// get event index
function getEventsIndex(listener, listeners) {

    let index = listeners.indexOf(listener);

    if (index > -1) return index;

    for (let i = 0; i < listeners.length; i++) {
        if (listener.name == listeners[i].name && listener.toString() == listeners[i].toString()) {
            return i;
        }
    }

    return -1;
}


function EventListener() { }

EventListener.prototype = {

    constructor: EventListener,

    on: function (type, listener) {
        if (!this._listeners) this._listeners = {};
        addEventListener(type, listener, this._listeners);
        return this;
    },

    once: function (type, listener) {
        if (!this._oneListener) this._oneListener = {};
        addEventListener(type, listener, this._oneListener);
        return this;
    },

    off: function (type, listener) {
        if (!this._listeners) this._listeners = {};
        if (!this._oneListener) this._oneListener = {};

        if (typeof listener === 'function') {
            removeEventListener(type, listener, this._listeners);
            removeEventListener(type, listener, this._oneListener);
        } else if (listener instanceof Array) {
            for (let fn of listener) {
                this.off(type, fn);
            }
        } else {
            delete this._listeners[type];
            delete this._oneListener[type];
        }

        return this;
    },

    //
    emit: function (type, events) {

        events = Array.prototype.slice.call(arguments).slice(1, arguments.length);

        if (this._listeners) {
            let listeners = this._listeners[type] ? this._listeners[type].slice() : [];

            if (listeners) {
                for (let listener of listeners) {
                    if (!listener) continue;
                    listener.apply(this, events);
                }
            }
        }

        if (this._oneListener) {
            let oneListeners = this._oneListener[type] ? this._oneListener[type].slice() : [];

            if (oneListeners) {
                for (let listener of oneListeners) {
                    if (!listener) continue;
                    listener.apply(this, events);
                    removeEventListener(type, listener, this._oneListener);
                }
            }
        }

        return this;
    },

    //
    mergeObjects: function () {
        //
        for (let i = 0; i < arguments.length; i++) {
            let options = arguments[i];
            for (let key in options) {
                if (this[key] !== undefined && options[key] !== undefined) {
                    this[key] = options[key];
                }
            }
        }
    }
}

export { EventListener };
